/*
 * Created by SharpDevelop.
 * User: maplo
 * Date: 1/20/2010
 * Time: 9:30 AM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Data;
using System.Data.OleDb;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Collections;
	
namespace Bulletin_Board
{
	/// <summary>
	/// Description of MainForm.
	/// </summary>
	public partial class MainForm : Form
	{
		//Keep list of barcodes in memory
		public String[] Barcodes;
		public String[] FrBarcodes;
		
		//Variables to store information on connection and messages
		public short FrBarcodesCount = 0;
		private TcpListener tcpLsn;
		private int ConnectID=0;
		private long SendConnectID=0;
		private long SendDeletedID=0;
		public long MessagesCounter =0;
		public long CurrentMessage = 0;
		private string ToHeader = "";
		private string FromHeader = "";
		public bool FormIsAlive = true;
		Thread tcpThd;
		
		//private Packet packet = new Packet();
		private Socket udps = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );
		
		//
		private Hashtable socketHolder = new Hashtable();
		private Hashtable threadHolder = new Hashtable();
		private Hashtable netHolder = new Hashtable();
		private Hashtable SendThreadHolder = new Hashtable();
		public Hashtable Messages = new Hashtable();
		Socket sckt;
		
		//Other variables
	
		
		// set delegate declaration to add a new message
		delegate void SetMessageEntry(string Message1);
		delegate void SendMesage1(string Mesage1, string Recipient1);
		
		//Add a text message
		public void NewMessageEntry(String Text1)
		{
			    if (this.InvokeRequired) 
			    {
			    	//Set variables to invoke function
        			SetMessageEntry callback = new SetMessageEntry(NewMessageEntry); 
        			bool InvokeIndicator = true;
        			int Counter = 0;
        			string Numbering = "";
        			
        			//Create loop to change text if it has already been sent.
        			while(InvokeIndicator == true)
        			{
	        			try{
        					//call delegate to add a new message
	        				this.Invoke(callback, Text1 + Numbering);
	        				InvokeIndicator = false;
	        			}catch(Exception e1)
	        			{
        					//Add a number to text that is matching
        					Counter++;
        					Numbering = "(" + Counter.ToString() + ")";
	        			}
        			}
    			}else 
			   	{
			    	//Add message into message viewer screen
			    	MessagesCounter++;
			    	CurrentMessage = MessagesCounter;
			    	
			    	this.MessagesBox.Text = Text1 + "\n\n" + MessagesCounter.ToString() + " of " + MessagesCounter.ToString();
			    	Messages.Add(MessagesCounter, MessagesBox.Text);
			    	this.NewMessage.Text = "";
    			}
		}
		
		public MainForm()
		{
			//
			// The InitializeComponent() call is required for Windows Forms designer support.
			//
			InitializeComponent();
			Timer2.Stop();
			//
			// TODO: Add constructor code after the InitializeComponent() call.
			//
		}
		
		void MainFormLoad(object sender, EventArgs e)
		{
			
			//Add options to send to multiple users
			AnalystList.Items.Add("All Analysts");
			AnalystList.Items.Add("All French Analysts");
			
			//Call function to load list of analysts
			LoadList();
			
			//Start Listening device
			Listen();
			
			AnalystList.SelectedIndex = 0;
		}
		
		//Function to load list of analysts from database
		private void LoadList()
		{
			//Establish a connection and get data
			string SQL = "SELECT * FROM Analysts ORDER BY FirstName, LastName;";
			string connString = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=F:\\CSI - HDI\\TempDB\\AnalystList2.mdb";
			OleDbConnection conn = new OleDbConnection(connString);
			OleDbCommand cmd = new OleDbCommand(SQL, conn);
			conn.Open();
			OleDbDataReader reader = cmd.ExecuteReader();
			
			//Set length to the list of barcodes
			Barcodes = new String[reader.FieldCount];
			FrBarcodes = new String[reader.FieldCount];
			
			//Add items to list of analysts and retreive barcodes
			int Counter = 0;
			
			//Get host name
			String strHostName = Dns.GetHostName();
			
			while(reader.Read())
			{
				//Add regular list
				AnalystList.Items.Add(reader["FirstName"].ToString()+ " " + reader["LastName"].ToString());
				Barcodes[Counter] = reader["Barcode"].ToString();
				
				//Add French barcodes
				if(reader["FrenchAnalyst"].ToString() == "True")
				{
					FrBarcodes[FrBarcodesCount] = reader["Barcode"].ToString();
					FrBarcodesCount++;
				}				
				
				//Verify user from barcode
				if(Barcodes[Counter].CompareTo(strHostName) != 1)
				{
					//MessageBox.Show(Barcodes[Counter].ToString());
					FromHeader = "From : " + reader["FirstName"].ToString()+ " " + reader["LastName"].ToString();
				}
				
				//Increase all barcodes counter				
				Counter++;
			}
			
			//End connection to the database
			reader.Close();
			conn.Close();
		}
		
		private void Listen()
		{	
			//Get host name
			String strHostName = Dns.GetHostName ();
			IPHostEntry ipEntry = Dns.GetHostEntry (strHostName);
			IPAddress [] addr = ipEntry.AddressList;
			
			//Start TcpListener
			tcpLsn = new TcpListener(addr[0], 1224);
			tcpLsn.Start();
			
			//Start new thread to read incoming data
			ThreadStart starter = new ThreadStart(WaitingForClient);
			tcpThd = new Thread(starter);	
			threadHolder.Add(ConnectID, tcpThd);
			tcpThd.Start();
		}
		
	
		//The following code is to be run as another thread to get data from client
		public void WaitingForClient()
		{
			
			while(true)
			{
				// Accept will block until someone connects
				sckt = tcpLsn.AcceptSocket();
				
				if(FormIsAlive == true)
				{
					ConnectID++; 
					if (ConnectID==0) ConnectID = 1;

					while (socketHolder.Contains(ConnectID) )
					{
						lock(this)
						{
							ConnectID++;
						}
					}

					
					//Create a thread for every incoming message
					Thread td = new Thread(new ThreadStart(ReadSocket));
					Net net = new Net();
					
					
					socketHolder.Add(ConnectID, sckt);
					threadHolder.Add(ConnectID, td);
					netHolder.Add(ConnectID, net);
					td.Start();
					
				}else
				{
					sckt.Close();
				}
			}
		}
		
		public void ReadSocket()
		{
			//Get socket data
			int realId = ConnectID;
			string tmp = "";
			Socket s = (Socket)socketHolder[realId];
			Net net = (Net)netHolder[realId];
			
			//Get string			
			tmp = net.ReadString( s );
			//MessageBox.Show(tmp);
			this.NewMessageEntry(tmp);
			
			//Close connection
			Thread thd = (Thread)threadHolder[realId];
			s.Close();
			if(thd.IsAlive)	thd.Abort();
		}
		
		public void MainFormFormClosing(object sender, FormClosingEventArgs e)
		{
			//Stop the server connection
			tcpLsn.Stop();
			FormIsAlive = false;
			tcpThd.Abort();
			Thread thd;
			
			//Stop all running processes
			for(int i = 0; i < threadHolder.Count;i++)
			{
				thd = (Thread)threadHolder[i];
				thd.Abort();
			}
			
			//Delete all expired threads for sending
			while(SendDeletedID < SendConnectID)
			{
				thd = (Thread)SendThreadHolder[SendDeletedID];
				
				if(thd.IsAlive)
				{
					thd.Abort();
				}
				SendThreadHolder.Remove(SendConnectID);
				SendDeletedID++;
			}
			Thread.Sleep(1000);
		}
		
		public void SendButtonClick(object sender, EventArgs e)
		{
			ToHeader = "To: " + AnalystList.SelectedItem.ToString();
			
			string Message1 = ToHeader + "\n" + FromHeader + "\n\n" + NewMessage.Text;
			//Create a loop for every user selected
			if(AnalystList.SelectedIndex!=1)
			{
				int LastItem;
				int CurrentItem;
				if(AnalystList.SelectedIndex==0)
				{
					LastItem = AnalystList.Items.Count - 3;
					CurrentItem = 0;
					
				}else
				{
					LastItem = AnalystList.SelectedIndex - 2;					
					CurrentItem = AnalystList.SelectedIndex - 2;
				}
				
				//Send text to all users selected
				while(CurrentItem <= LastItem)
				{
					//Send message in a new Thread 
					SendMessage SendMessage1 = new SendMessage(Barcodes[CurrentItem], Message1);
					Thread td1 = new Thread (SendMessage1.SendMessageText);
					td1.Start();
					SendThreadHolder.Add(SendConnectID, td1);
					
					//record this thread number and start timer to end thread
					CurrentItem++;
					SendConnectID++;
					Timer2.Start();
				}
			}else
			{
				//Run loop to send to all french analysts
				for(int i = 0; i < FrBarcodesCount; i++)
				{	
					//Send message in a new Thread 
					SendMessage SendMessage1 = new SendMessage(FrBarcodes[i], Message1);
					Thread td1 = new Thread (SendMessage1.SendMessageText);
					td1.Start();
					SendThreadHolder.Add(SendConnectID, td1);
					
					//record this thread number and start timer to end thread
					SendConnectID++;
					Timer2.Start();
				}
			}
		}
			
		
		void SendMessage(string HostReceiver, string TextMessage)
		{		
			//Get IP address and start connection
			Socket Socket1 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
			IPHostEntry IPEntry = Dns.GetHostEntry (HostReceiver);
			IPAddress Addr1 = IPAddress.Parse(IPEntry.AddressList[0].ToString());
			IPEndPoint EPhost = new IPEndPoint( Addr1, 1224 );
			
			Net net = new Net();

			try
			{
				//Start connection
				Socket1.Connect(EPhost);
				
				//If connection established send data
				if (Socket1.Connected)
				{
					net.SendString( Socket1, TextMessage);
					Socket1.Close();
				}
				else
				{
					Socket1.Close();
				}
			}
			catch (Exception e1)
			{
				MessageBox.Show(e1.ToString());
				Socket1.Close();
			}
		}
		

		//Go to the previous message
		void BackButtonClick(object sender, EventArgs e)
		{
			if(CurrentMessage > 1)
			{
				CurrentMessage = CurrentMessage - 1;
				MessagesBox.Text = (string)Messages[CurrentMessage];
			}
		}
		
		//Go to the next message
		void ForwardButtonClick(object sender, EventArgs e)
		{
			if(CurrentMessage < MessagesCounter)
			{
				CurrentMessage++;
				MessagesBox.Text = (string)Messages[CurrentMessage];
			}
		}
		
		//Remove a stored message
		void DeleteButtonClick(object sender, EventArgs e)
		{
			
			//Delete item selected by moving messages and deleting last item
			if(MessagesCounter > 1)
			{
				for(long i = CurrentMessage; i < Messages.Count;i++)
				{
					Messages[i] = Messages[i + 1];
				}
				Messages.Remove(Messages.Count);
				if(CurrentMessage != 1)
				{
					CurrentMessage--;	
				}
				MessagesCounter--;
				MessagesBox.Text = (string)Messages[CurrentMessage];
			}else 
			{	if(MessagesCounter == 1)
				{
					CurrentMessage = 0;
					MessagesCounter = 0;
					MessagesBox.Text = "";
					Messages.Remove(0);
				}		
			}
		}
		
		void EndAllThreads(object sender, EventArgs e)
		{
			Thread thd;
			//Delete all expired threads
			while(SendDeletedID < SendConnectID)
			{
				thd = (Thread)SendThreadHolder[SendDeletedID];
				
				if(thd.IsAlive)
				{
					//MessageBox.Show("Got here");
					thd.Abort();
				}
				//SendThreadHolder[SendDeletedID].
				SendThreadHolder.Remove(SendConnectID);
				SendDeletedID++;
			}
			Timer2.Stop();
		}
		
		void AboutGWLBulletinBoardToolStripMenuItemClick(object sender, EventArgs e)
		{
			AboutBB AboutBB1 = new AboutBB();
			AboutBB1.Show();
		}
		
		void MainFormFormClosed(object sender, FormClosedEventArgs e)
		{
		}
		
		void CloseToolStripMenuItemClick(object sender, EventArgs e)
		{
			this.Close();
		}
		
		void Button1Click(object sender, EventArgs e)
		{
			tcpThd.Abort();
		}
	}
	
	//This class simplifies data transmission
	public class Net
	{
		public byte[] data_buf, len_buf;

		public Net()
		{ 
			data_buf = new byte[10000]; 
			len_buf = new byte[4]; 
		}

		public string ReadString( Socket s )
		{
			string st = null;
			int ret,size;
			ret = s.Receive( len_buf, 4, 0 );
			size = BitConverter.ToInt32( len_buf, 0 );
			if (ret > 0)
			{
				ret = s.Receive( data_buf, size, 0 );
				if (ret > 0)
					st = System.Text.Encoding.ASCII.GetString( data_buf, 0, ret );
			}
			return st;
		}


		public void SendString( Socket s, string str )
		{
			len_buf = BitConverter.GetBytes( str.Length );
			s.Send( len_buf, 4, 0 );
			s.Send( System.Text.Encoding.ASCII.GetBytes(str), str.Length, 0 );
		}

		public void SendBytes( Socket s, byte[] b, int length )
		{
			int ret=0;
			len_buf = BitConverter.GetBytes( length );
			s.Send( len_buf, 4, 0 );
			ret = s.Send( b, length, 0 );
		}

		public int ReadBytes( Socket s )
		{
			int ret,size;
			ret = s.Receive( len_buf, 4, 0 );
			size = BitConverter.ToInt32( len_buf, 0 );
			if (ret > 0 && size > 0)
				ret = s.Receive( data_buf, size, 0 );
			return ret;
		}

	}

}
